// META: title=test WebNN API instanceNormalization operation
// META: global=window,dedicatedworker
// META: variant=?cpu
// META: variant=?gpu
// META: variant=?npu
// META: script=../resources/utils.js
// META: timeout=long

'use strict';

// https://www.w3.org/TR/webnn/#api-mlgraphbuilder-instancenorm
// Normalize the input using Instance-Normalization.
//
// dictionary MLInstanceNormalizationOptions {
//   MLOperand scale;
//   MLOperand bias;
//   double epsilon = 1e-5;
//   MLInputOperandLayout layout = "nchw";
// };
//
// MLOperand instanceNormalization(
//     MLOperand input, optional MLInstanceNormalizationOptions options = {});


const getInstanceNormPrecisionTolerance = (graphResources) => {
  // according to
  // https://github.com/web-platform-tests/wpt/pull/43891#discussion_r1457026316
  const toleranceValueDict = {float32: 840, float16: 8400};
  const expectedDataType =
      getExpectedDataTypeOfSingleOutput(graphResources.expectedOutputs);
  return {metricType: 'ULP', value: toleranceValueDict[expectedDataType]};
};

const instanceNormTests = [
  {
    'name': 'instanceNormalization float32 4D tensor default options',
    'graph': {
      'inputs': {
        'instanceNormInput': {
          'data': [
            -97.949951171875,    29.44037628173828,  -73.92131042480469,
            -38.11185836791992,  41.33772659301758,  -59.77853012084961,
            -74.66901397705078,  -68.16508483886719, 35.82481384277344,
            -6.948329448699951,  54.42462158203125,  47.53074645996094,
            66.93562316894531,   76.74034881591797,  5.6758809089660645,
            25.68659210205078,   37.37651062011719,  56.252689361572266,
            -16.574905395507812, 42.949893951416016, 73.8739242553711,
            -99.00035095214844,  -33.11322784423828, -17.380685806274414
          ],
          'descriptor': {'dimensions': [2, 3, 2, 2], 'dataType': 'float32'}
        }
      },
      'operators': [{
        'name': 'instanceNormalization',
        'arguments': [{'input': 'instanceNormInput'}],
        'outputs': 'instanceNormOutput'
      }],
      'expectedOutputs': {
        'instanceNormOutput': {
          'data': [
            -1.0995290279388428, 1.5525832176208496,  -0.5992818474769592,
            0.14622758328914642, 1.72129487991333,    -0.41020718216896057,
            -0.7240943908691406, -0.586993396282196,  0.13073226809501648,
            -1.6633318662643433, 0.9108771681785583,  0.6217224597930908,
            0.7947131395339966,  1.1309205293655396,  -1.3059037923812866,
            -0.6197298169136047, 0.2657700479030609,  0.9459608793258667,
            -1.6783342361450195, 0.46660327911376953, 1.5037200450897217,
            -1.2981476783752441, -0.2302791178226471, 0.024706769734621048
          ],
          'descriptor': {'dimensions': [2, 3, 2, 2], 'dataType': 'float32'}
        }
      }
    }
  },
  {
    'name': 'instanceNormalization float32 4D tensor options.scale',
    'graph': {
      'inputs': {
        'instanceNormInput': {
          'data': [
            -97.949951171875,    29.44037628173828,  -73.92131042480469,
            -38.11185836791992,  41.33772659301758,  -59.77853012084961,
            -74.66901397705078,  -68.16508483886719, 35.82481384277344,
            -6.948329448699951,  54.42462158203125,  47.53074645996094,
            66.93562316894531,   76.74034881591797,  5.6758809089660645,
            25.68659210205078,   37.37651062011719,  56.252689361572266,
            -16.574905395507812, 42.949893951416016, 73.8739242553711,
            -99.00035095214844,  -33.11322784423828, -17.380685806274414
          ],
          'descriptor': {'dimensions': [2, 3, 2, 2], 'dataType': 'float32'}
        },
        'instanceNormScale': {
          'data': [-94.42772674560547, 66.69620513916016, -98.56572723388672],
          'descriptor': {'dimensions': [3], 'dataType': 'float32'},
          'constant': true
        }
      },
      'operators': [{
        'name': 'instanceNormalization',
        'arguments': [
          {'input': 'instanceNormInput'},
          {'options': {'scale': 'instanceNormScale'}}
        ],
        'outputs': 'instanceNormOutput'
      }],
      'expectedOutputs': {
        'instanceNormOutput': {
          'data': [
            103.8260269165039,   -146.60690307617188, 56.58882141113281,
            -13.807937622070312, 114.80384063720703,  -27.359262466430664,
            -48.29434585571289,  -39.150230407714844, -12.885721206665039,
            163.94752502441406,  -89.78126525878906,  -61.2805290222168,
            -75.04296112060547,  -106.79025268554688, 123.31352996826172,
            58.51968002319336,   17.725852966308594,  63.09199905395508,
            -111.93852233886719, 31.120668411254883,  -148.2152557373047,
            127.95286560058594,  22.697628021240234,  -2.4352407455444336
          ],
          'descriptor': {'dimensions': [2, 3, 2, 2], 'dataType': 'float32'}
        }
      }
    }
  },
  {
    'name': 'instanceNormalization float32 4D tensor options.bias',
    'graph': {
      'inputs': {
        'instanceNormInput': {
          'data': [
            -97.949951171875,    29.44037628173828,  -73.92131042480469,
            -38.11185836791992,  41.33772659301758,  -59.77853012084961,
            -74.66901397705078,  -68.16508483886719, 35.82481384277344,
            -6.948329448699951,  54.42462158203125,  47.53074645996094,
            66.93562316894531,   76.74034881591797,  5.6758809089660645,
            25.68659210205078,   37.37651062011719,  56.252689361572266,
            -16.574905395507812, 42.949893951416016, 73.8739242553711,
            -99.00035095214844,  -33.11322784423828, -17.380685806274414
          ],
          'descriptor': {'dimensions': [2, 3, 2, 2], 'dataType': 'float32'}
        },
        'instanceNormBias': {
          'data': [-33.048641204833984, 4.511423587799072, -37.93617248535156],
          'descriptor': {'dimensions': [3], 'dataType': 'float32'},
          'constant': true
        }
      },
      'operators': [{
        'name': 'instanceNormalization',
        'arguments': [
          {'input': 'instanceNormInput'},
          {'options': {'bias': 'instanceNormBias'}}
        ],
        'outputs': 'instanceNormOutput'
      }],
      'expectedOutputs': {
        'instanceNormOutput': {
          'data': [
            -34.148170471191406, -31.496057510375977, -33.64792251586914,
            -32.90241241455078,  6.232718467712402,   4.1012163162231445,
            3.7873291969299316,  3.9244301319122314,  -37.80543899536133,
            -39.59950256347656,  -37.02529525756836,  -37.314449310302734,
            -32.253929138183594, -31.917720794677734, -34.35454559326172,
            -33.66836929321289,  4.777193546295166,   5.4573845863342285,
            2.8330893516540527,  4.978026866912842,   -36.43245315551758,
            -39.23432159423828,  -38.16645050048828,  -37.91146469116211
          ],
          'descriptor': {'dimensions': [2, 3, 2, 2], 'dataType': 'float32'}
        }
      }
    }
  },
  {
    'name': 'instanceNormalization float32 4D tensor options.epsilon',
    'graph': {
      'inputs': {
        'instanceNormInput': {
          'data': [
            -97.949951171875,    29.44037628173828,  -73.92131042480469,
            -38.11185836791992,  41.33772659301758,  -59.77853012084961,
            -74.66901397705078,  -68.16508483886719, 35.82481384277344,
            -6.948329448699951,  54.42462158203125,  47.53074645996094,
            66.93562316894531,   76.74034881591797,  5.6758809089660645,
            25.68659210205078,   37.37651062011719,  56.252689361572266,
            -16.574905395507812, 42.949893951416016, 73.8739242553711,
            -99.00035095214844,  -33.11322784423828, -17.380685806274414
          ],
          'descriptor': {'dimensions': [2, 3, 2, 2], 'dataType': 'float32'}
        }
      },
      'operators': [{
        'name': 'instanceNormalization',
        'arguments': [
          {'input': 'instanceNormInput'}, {'options': {'epsilon': 0.000001}}
        ],
        'outputs': 'instanceNormOutput'
      }],
      'expectedOutputs': {
        'instanceNormOutput': {
          'data': [
            -1.0995290279388428, 1.5525832176208496,  -0.5992818474769592,
            0.14622758328914642, 1.72129487991333,    -0.41020718216896057,
            -0.7240943908691406, -0.586993396282196,  0.13073226809501648,
            -1.6633318662643433, 0.9108771681785583,  0.6217224597930908,
            0.7947131991386414,  1.1309205293655396,  -1.3059037923812866,
            -0.6197298765182495, 0.2657700479030609,  0.9459608793258667,
            -1.6783342361450195, 0.46660327911376953, 1.5037200450897217,
            -1.2981476783752441, -0.2302791178226471, 0.024706769734621048
          ],
          'descriptor': {'dimensions': [2, 3, 2, 2], 'dataType': 'float32'}
        }
      }
    }
  },
  {
    'name':
        'instanceNormalization float32 4D tensor explict options.layout=\'nchw\'',
    'graph': {
      'inputs': {
        'instanceNormInput': {
          'data': [
            -97.949951171875,    29.44037628173828,  -73.92131042480469,
            -38.11185836791992,  41.33772659301758,  -59.77853012084961,
            -74.66901397705078,  -68.16508483886719, 35.82481384277344,
            -6.948329448699951,  54.42462158203125,  47.53074645996094,
            66.93562316894531,   76.74034881591797,  5.6758809089660645,
            25.68659210205078,   37.37651062011719,  56.252689361572266,
            -16.574905395507812, 42.949893951416016, 73.8739242553711,
            -99.00035095214844,  -33.11322784423828, -17.380685806274414
          ],
          'descriptor': {'dimensions': [2, 3, 2, 2], 'dataType': 'float32'}
        }
      },
      'operators': [{
        'name': 'instanceNormalization',
        'arguments':
            [{'input': 'instanceNormInput'}, {'options': {'layout': 'nchw'}}],
        'outputs': 'instanceNormOutput'
      }],
      'expectedOutputs': {
        'instanceNormOutput': {
          'data': [
            -1.0995290279388428, 1.5525832176208496,  -0.5992818474769592,
            0.14622758328914642, 1.72129487991333,    -0.41020718216896057,
            -0.7240943908691406, -0.586993396282196,  0.13073226809501648,
            -1.6633318662643433, 0.9108771681785583,  0.6217224597930908,
            0.7947131395339966,  1.1309205293655396,  -1.3059037923812866,
            -0.6197298169136047, 0.2657700479030609,  0.9459608793258667,
            -1.6783342361450195, 0.46660327911376953, 1.5037200450897217,
            -1.2981476783752441, -0.2302791178226471, 0.024706769734621048
          ],
          'descriptor': {'dimensions': [2, 3, 2, 2], 'dataType': 'float32'}
        }
      }
    }
  },
  {
    'name': 'instanceNormalization float32 4D tensor options.layout=\'nhwc\'',
    'graph': {
      'inputs': {
        'instanceNormInput': {
          'data': [
            -97.949951171875,   41.33772659301758,   35.82481384277344,
            29.44037628173828,  -59.77853012084961,  -6.948329448699951,
            -73.92131042480469, -74.66901397705078,  54.42462158203125,
            -38.11185836791992, -68.16508483886719,  47.53074645996094,
            66.93562316894531,  37.37651062011719,   73.8739242553711,
            76.74034881591797,  56.252689361572266,  -99.00035095214844,
            5.6758809089660645, -16.574905395507812, -33.11322784423828,
            25.68659210205078,  42.949893951416016,  -17.380685806274414
          ],
          'descriptor': {'dimensions': [2, 2, 2, 3], 'dataType': 'float32'}
        }
      },
      'operators': [{
        'name': 'instanceNormalization',
        'arguments':
            [{'input': 'instanceNormInput'}, {'options': {'layout': 'nhwc'}}],
        'outputs': 'instanceNormOutput'
      }],
      'expectedOutputs': {
        'instanceNormOutput': {
          'data': [
            -1.0995290279388428, 1.72129487991333,     0.13073226809501648,
            1.5525832176208496,  -0.41020718216896057, -1.6633318662643433,
            -0.5992818474769592, -0.7240943908691406,  0.9108771681785583,
            0.14622758328914642, -0.586993396282196,   0.6217224597930908,
            0.7947131395339966,  0.2657700479030609,   1.5037200450897217,
            1.1309205293655396,  0.9459608793258667,   -1.2981476783752441,
            -1.3059037923812866, -1.6783342361450195,  -0.2302791178226471,
            -0.6197298169136047, 0.46660327911376953,  0.024706769734621048
          ],
          'descriptor': {'dimensions': [2, 2, 2, 3], 'dataType': 'float32'}
        }
      }
    }
  },
  {
    'name': 'instanceNormalization float32 4D tensor all options',
    'graph': {
      'inputs': {
        'instanceNormInput': {
          'data': [
            -97.949951171875,   41.33772659301758,   35.82481384277344,
            29.44037628173828,  -59.77853012084961,  -6.948329448699951,
            -73.92131042480469, -74.66901397705078,  54.42462158203125,
            -38.11185836791992, -68.16508483886719,  47.53074645996094,
            66.93562316894531,  37.37651062011719,   73.8739242553711,
            76.74034881591797,  56.252689361572266,  -99.00035095214844,
            5.6758809089660645, -16.574905395507812, -33.11322784423828,
            25.68659210205078,  42.949893951416016,  -17.380685806274414
          ],
          'descriptor': {'dimensions': [2, 2, 2, 3], 'dataType': 'float32'}
        },
        'instanceNormScale': {
          'data': [-94.42772674560547, 66.69620513916016, -98.56572723388672],
          'descriptor': {'dimensions': [3], 'dataType': 'float32'},
          'constant': true
        },
        'instanceNormBias': {
          'data': [-33.048641204833984, 4.511423587799072, -37.93617248535156],
          'descriptor': {'dimensions': [3], 'dataType': 'float32'},
          'constant': true
        }
      },
      'operators': [{
        'name': 'instanceNormalization',
        'arguments': [
          {'input': 'instanceNormInput'}, {
            'options': {
              'scale': 'instanceNormScale',
              'bias': 'instanceNormBias',
              'epsilon': 0.000001,
              'layout': 'nhwc'
            }
          }
        ],
        'outputs': 'instanceNormOutput'
      }],
      'expectedOutputs': {
        'instanceNormOutput': {
          'data': [
            70.77738189697266,   119.31526184082031,  -50.821895599365234,
            -179.65554809570312, -22.847837448120117, 126.01134490966797,
            23.540178298950195,  -43.782920837402344, -127.71744537353516,
            -46.8565788269043,   -34.6388053894043,   -99.2166976928711,
            -108.09159851074219, 22.237276077270508,  -186.15142822265625,
            -139.83889770507812, 67.60342407226562,   90.01669311523438,
            90.26488494873047,   -107.4271011352539,  -15.238543510437012,
            25.471038818359375,  35.6320915222168,    -40.37141418457031
          ],
          'descriptor': {'dimensions': [2, 2, 2, 3], 'dataType': 'float32'}
        }
      }
    }
  }
];

if (navigator.ml) {
  instanceNormTests.forEach((test) => {
    webnn_conformance_test(
        buildGraphAndCompute, getInstanceNormPrecisionTolerance, test);
  });
} else {
  test(() => assert_implements(navigator.ml, 'missing navigator.ml'));
}
